/*
	Filename	:	bjRules.cpp
	Author(s)	:	Ray E. Bornert II
	Date		:	2002-MAR-26
	Copyright	:	(c) 2002 RealTimeGaming

	History		:
*/

//////////////
// INCLUDES //
//////////////
#include "bjrules.h"
#include <string.h>

//forward declare for Cardset routine
int IsCardsInSet( unsigned char *pCards, int nCards, unsigned char *pSet );

//card values
int BJRules::m_cardValue[64] =
{
	0,0,0,0,	//<unused>
	1,1,1,1,	//ace
	2,2,2,2,	//two
	3,3,3,3,	//three
	4,4,4,4,	//four
	5,5,5,5,	//five
	6,6,6,6,	//six
	7,7,7,7,	//seven
	8,8,8,8,	//eight
	9,9,9,9,	//nine
	10,10,10,10,//ten
	10,10,10,10,//jack
	10,10,10,10,//queen
	10,10,10,10,//king
	1,1,1,1,	//ace
	0,0,0,0		//<unused>
};

BJRules::BJRules()
{
	//normalize all bits to zero
	memset(this,0,sizeof(BJRules));
	m_nBJBets = 1;

}

BJRules::BJRules( int ruleSetId )
{
	//normalize all bits to zero
	memset(this,0,sizeof(BJRules));

	switch(ruleSetId)
	{
	default:
		case 0 :	
		case 10: /* CSN-5092: BJ in sports */	
					InitRules_StandardBlackjack();	break;
		case 1 :	InitRules_Pontoon();			break;
		case 2 :	InitRules_DoubleExposure21();	break;
		// bwardlow 29-Aug-2006 #14722 disable Caribbean 21
		//case 3 :	InitRules_Caribbean21();		break;
		case 4 :	InitRules_Super21();			break;
		case 5 :	InitRules_Spanish21();			break;
		case 6 :	InitRules_PerfectPairs();		break;
		case 11 :	InitRules_Zappit();				break; /// [2013-07-09] Charles, Added for supporting 'Zappit Rackcard'.
	}

	//remember the rule set id
	m_ruleSetId = ruleSetId;
}

int BJRules::CardCode( int index )
{
	int rank = 1 + (index / 4);
	int suit = 1 + (index % 4);
	int card = CardCode( rank, suit );
	return card;
}

int BJRules::CardCode( int rank, int suit )
{
	rank &= 0x0f;
	suit &= 0x0f;

	int card = (suit << 4) | rank;

	return card;
}

int BJRules::CardSuit( int card )
{
	int suit = (card >> 4) & 0x0f;
	return suit;
}

int BJRules::CardRank( int card )
{
	int rank = (card >> 0) & 0x0f;
	return rank;
}

int BJRules::CardIndex( int card )
{
	int rank = CardRank( card );
	int suit = CardSuit( card );
	int index = (rank*4)+suit-1;
	return index;
}

int BJRules::CardValue( int card )
{
	int index = CardIndex( card );
	int value = m_cardValue[ index ];
	return value;
}

int BJRules::CardRankValue( unsigned char rank )
{
	return m_cardValue[ rank*4 ];
}

int BJRules::GetHandTotal( BJHand* pHand, int* isSoft )
{
	int total = pHand->GetScore();
	return total;
}

int BJRules::IsSignaledAction( BJHand* pHand, GameAction action )
{
	int signaled=0;
	switch (action)
	{
	case Bet		:	signaled= pHand->wasAction( BJF_BET			);	break;
	case Hit		:	signaled= pHand->wasAction( BJF_HIT			);	break;
	case Stand		:	signaled= pHand->wasAction( BJF_STAND		);	break;
	case Double		:	signaled= pHand->wasAction( BJF_DOUBLE		);	break;
	case Split		:	signaled= pHand->wasAction( BJF_SPLIT		);	break;
	case Surrender	:	signaled= pHand->wasAction( BJF_SURRENDER	);	break;
	case Zap	:	signaled= pHand->wasAction( BJF_ZAP);	break;		/// [2013-07-10] Charles. Added for supporting 'Zappit Rackcard'.
	default			:	signaled= false;
	}
	return signaled;
}


int BJRules::IsPrecluded( BJHand* pHand, GameAction action )
{
	//some actions can disable others
	for (int i=0; i<MAXACTION; i++)
	if (m_preclusion[i][action]==0)			//action not allowed after i
	if (IsSignaledAction(pHand,(GameAction)i))	//has i occured
		return (1);

	//action is not precluded (is allowed)
	return (0);
}

int BJRules::CanPlayer( GameAction action, BJHand* pHand, int nHands )
{
	for (int i=0; i<m_nActionRules; i++)
	{
		BJAction* pAction= &m_actionRules[i];
		if (pAction->IsAllowed( 'P', action, pHand, nHands ))
		{
			if ( action == EOG)
				return (1);

			if ( !IsPrecluded( pHand, action ))
				return (1);
		}
	}

	//not allowed
	return 0;
}

int BJRules::CanDealer( GameAction action, BJHand* pHand, int nHands )
{
	for (int i=0; i<m_nActionRules; i++)
	{
		BJAction* pAction= &m_actionRules[i];
		if (pAction->IsAllowed( 'D', action, pHand, nHands ))
			return (1);
	}

	//not allowed
	return 0;
}

int BJRules::CanPlayerBet( BJHand* pHand, int nHands )
{
	int iResult;

	//BET
	iResult = CanPlayer( Bet, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//the action is allowed
	return (1);
}

void BJRules::KeepThePlayerSafe( BJHand* pPlayer, int nHands, BJHand* pDealer, int* pOptions )
{
	//gotta have 2 or more dealer cards visible
	int nDealerCardsVisible = pDealer->GetNCardsVisible();
	if (nDealerCardsVisible <= 1)
		return;

	//all dealer cards must be visible
	int nDealerCards		= pDealer->getCount();
	if (nDealerCards != nDealerCardsVisible)
		return;

	//we must know that the dealer will not hit (stand)
	int dealerWillHit		= CanDealer( Hit, pDealer, nHands );
	if (dealerWillHit)
		return;

	//the player cannot have doubled
	int playerHasDoubled	= IsSignaledAction( pPlayer, Double );
	if (playerHasDoubled)
		return;

	//get the scores
	int dealerTotal			= pDealer->GetScore();
	int playerTotal			= pPlayer->GetScore();

	//player will win
	if (playerTotal > dealerTotal)
	{
		//do not let the player take a card
		*pOptions &= (~OPTION_FLAG(Hit));
		*pOptions &= (~OPTION_FLAG(Double));
	}
	else
	//dealer will win
	if (playerTotal <= dealerTotal)
	{
		//do not let the player stand
		*pOptions &= (~OPTION_FLAG(Stand));
	}

	//DEFECT 730
	//there must be at least one player action defined
	if (*pOptions == 0)
	{
		//allow STAND
		*pOptions |= (OPTION_FLAG(Stand));
	}
}

int BJRules::CanPlayerHit( BJHand* pHand, int nHands )
{
	int iResult;

	//HIT
	iResult = CanPlayer( Hit, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//the action is allowed
	return (1);
}

int BJRules::CanPlayerStand( BJHand* pHand, int nHands )
{
	int iResult;

	//STAND
	iResult = CanPlayer( Stand, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//the action is allowed
	return (1);
}

int BJRules::CanPlayerDouble( BJHand* pHand, int nHands )
{
	int iResult;

	//DOUBLE
	iResult = CanPlayer( Double, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//how many cards in the hand
	int nBets = pHand->GetNBets();

	//maximum of 128 bets
	if (nBets > 64)
		return (0);

	//the action is allowed
	return (1);
}

int BJRules::CanPlayerSplit( BJHand* pHand, int nHands )
{
	int iResult;

	//hard cap for max hands
	if (nHands >= m_maximumHands)
		return (0);

	//SPLIT
	iResult = CanPlayer( Split, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//how many cards in the hand
	int nCards = pHand->getCount();

	//gotta have 2 cards to do a split
	if (nCards != 2)
		return (0);

	//the action is allowed
	return (1);
}

int BJRules::CanPlayerSurrender( BJHand* pHand, int nHands)
{
	int iResult;

	//SURRENDER
	iResult = CanPlayer( Surrender, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//the action is allowed
	return (1);
}

/// [2013-07-09] Charles. Added for supporting 'Zappit Rackcard'.
int BJRules::CanPlayerZap( BJHand* pHand, int nHands )
{
	int iResult;

	//SURRENDER
	iResult = CanPlayer( Zap, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//the action is allowed
	return (1);
}

int BJRules::CanPlayerInsure( BJHand* pDealer )
{
	//no insure bet yet
	//dealer has one and only one card showing
	//the dealer has not more than 2 cards
	//the visible card is an ace

	int maxNDealerCards = IsSoftAces() ? 2 : 3;

	if (m_insureBet > 0)
	if (pDealer->getCount()	<= maxNDealerCards)
	if (pDealer->GetNCardsVisible() == 1)
	if (pDealer->IsAceShowing())
		return (1);

	//insurance is not allowed
	return (0);
}

int BJRules::GetPlayerOptions( BJHand* pHand, int nHands, BJHand* pDealer )
{
	//no options defined for negative number of hands
	if (nHands < 0)
		return 0;

	// FogBugz 244: prohibit server crashes when pHand is null.
	if (pHand == 0)
		return 0;

	//how many cards in the hand
	int nCards = pHand->getCount();

	//no options defined for negative number of cards
	if (nCards < 0)
		return 0;

	//get a pointer to the array of cards
	uint8* pCards = pHand->getCards();

	//no options defined when the card list is inaccessible
	if (nCards > 0)
	if (pCards == 0)
		return (0);

	//default is player has no options
	int options = 0;

	//get all the option flags
	int canBet			= CanPlayerBet		(pHand, nHands );
	int canHit			= CanPlayerHit		(pHand, nHands );
	int canStand		= CanPlayerStand	(pHand, nHands );
	int	canSplit		= CanPlayerSplit	(pHand, nHands );
	int canDouble		= CanPlayerDouble	(pHand, nHands );
	int canSurrender	= CanPlayerSurrender(pHand, nHands );
	int canZap= CanPlayerZap(pHand, nHands );					/// [2013-07-10] Charles. Added for supporting 'Zappit Rackcard'.
	
	//set the individual bits
	if (canBet)			options |= OPTION_FLAG(Bet);
	if (canHit)			options |= OPTION_FLAG(Hit);
	if (canStand)		options |= OPTION_FLAG(Stand);
	if (canSplit)		options |= OPTION_FLAG(Split);
	if (canDouble)		options |= OPTION_FLAG(Double);
	if (canSurrender)	options |= OPTION_FLAG(Surrender);
	if (canZap)	options |= OPTION_FLAG(Zap);		/// [2013-07-10] Charles. Added for supporting 'Zappit Rackcard'.

	KeepThePlayerSafe( pHand, nHands, pDealer, &options );

	//return the set of player options
	return options;
}


int BJRules::CanDealerHit( BJHand* pHand, int nHands )
{
	int iResult;

	//HIT
	iResult = CanDealer( Hit, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//the action is allowed
	return (1);
}

int BJRules::CanDealerStand( BJHand* pHand, int nHands )
{
	int iResult;

	//HIT
	iResult = CanDealer( Stand, pHand, nHands );

	//is the action disallowed
	if (iResult == 0)
		return (0);

	//the action is allowed
	return (1);
}

int BJRules::GetDealerOptions( BJHand* pHand, int nHands )
{
	//default is dealer has no options
	int options=0;

	//how many cards in the hand
	int nCards = pHand->getCount();

	//no options defined for negative number of cards
	if (nCards < 0)
		return 0;

	//get a pointer to the array of cards
	uint8* pCards = pHand->getCards();

	if (nCards > 0)
	{
		if (pCards == 0)
			return (0);
	}

	//get all the option flags
	int canHit			= CanDealerHit	( pHand, nHands );
	int canStand		= CanDealerStand( pHand, nHands );

	//set the individual bits
	if (canHit)			options |= OPTION_FLAG(Hit);
	if (canStand)		options |= OPTION_FLAG(Stand);

	//return the set of dealer options
	return options;
}

int BJRules::CanPayout( int bet, BJHand* pDealer )
{
	//default to no
	int canpayout=0;

	if( bet	> 0 )					//player made the bet
		if( pDealer->getCount() >= (IsSoftAces() ? 2 : 3) )	//dealer has at least 2 cards
			canpayout=1;

	return canpayout;
}

int BJRules::GetPayout( GameSidebet sidebet, int bet, BJHand* pPlayer, BJHand* pDealer )
{
	//default to push
	int payout=0;

	switch( sidebet )
	{
	case Insure:
		if (pDealer->IsNatural())
			payout = (int)(bet*(m_insurePayout + 1));
		else
			payout = 0;
		break;
	}

	return payout;
}

//position of of dealers first card dealt face up on the deal
int BJRules::GetPositionDUC()
{
	int nCard=0;
	for (int i=0; i<m_dealScriptLen; i++)
	{
		char script = m_dealScript[i];

		if (script == 'D')
			return nCard;
		
		if (script == 'd')
			nCard++;
	}
	return (-1);
}

BJBonus* BJRules::GetPlayerWinBonus( BJHand* pPlayer, int nHands, BJHand* pDealer )
{
	//get the DUC
	unsigned char duc = 0;
	if (pDealer)
	{
		int nDUC = GetPositionDUC();
		if (nDUC >= 0)
			duc = pDealer->getCardAt( nDUC );
	}

	for (int i=0; i<m_nBonusRules; i++)
	{
		BJBonus* pBonus= &m_bonusRules[i];
		if (pBonus->GetWho() == 'P')	//player
		if (pBonus->GetType() == 'W')	//win
		if (pBonus->IsPlayerHandQualified( pPlayer, nHands, duc ))
			return pBonus;
	}

	return NULL;
}

BJBonus* BJRules::GetDealerWinBonus( BJHand* pHand, int nHands )
{
	for (int i=0; i<m_nBonusRules; i++)
	{
		BJBonus* pBonus = &m_bonusRules[i];
		if (pBonus->GetWho() == 'D')	//dealer
		if (pBonus->GetType() == 'W')	//win
		if (pBonus->IsDealerHandQualified( pHand, nHands ))
			return pBonus;
	}

	return NULL;
}

BJBonus* BJRules::GetDealerWinBonusPossible( BJHand* pHand, int nHands )
{
	for (int i=0; i<m_nBonusRules; i++)
	{
		BJBonus* pBonus = &m_bonusRules[i];
		if (pBonus->GetWho() == 'D')	//dealer
		if (pBonus->GetType() == 'W')	//win
		if (pBonus->IsDealerHandPossible( pHand, nHands ))
			return pBonus;
	}

	return NULL;
}

int BJRules::GetPayout
(
	int bet,
	BJHand* pPlayer,
	BJHand* pDealer,
	int nHands,
	char** ppPlayerBonusName,
	char** ppDealerBonusName
)
{
	//default to push
	int payout = 0;

	//handle the surrender case
	if (pPlayer->wasAction(BJF_SURRENDER))
	{
		payout = (int)(bet*m_surrenderPayout);
		return payout;
	}

	int playerTotal		= pPlayer->GetScore();
	int dealerTotal		= pDealer->GetScore();
	int playerScore		= playerTotal;
	int dealerScore		= dealerTotal; 

	int playerBonusTotal=0;
	int dealerBonusTotal=0;
	float playerBonusPayout=0.0;
	float dealerBonusPayout=0.0;

	BJBonus* pPlayerBonus = GetPlayerWinBonus( pPlayer, nHands, pDealer );
	BJBonus* pDealerBonus = GetDealerWinBonus( pDealer, nHands );

	/// [2013-07-25] Charles. Added for supporting 'Zappit Rackcard'.
	if (pPlayerBonus != 0x00) {
		// If 'Zapped Blackjack', Ignore bonus. It pays 1:1.
		if(stricmp(pPlayerBonus->GetName(), "BlackJack") == 0 && pPlayer->wasAction(BJF_ZAP)) {
			pPlayerBonus = 0x00;		// Ignore bonus
		}
	}

	if (playerTotal >= m_playerBustTotal)
		playerScore = 0;
	else
	if (pPlayerBonus)
	{
		playerBonusTotal += pPlayerBonus->GetBonusTotal();
		playerBonusPayout += pPlayerBonus->GetBonusPayout();
		*ppPlayerBonusName = pPlayerBonus->GetName();
	}

	if (dealerTotal >= m_dealerBustTotal) {
		dealerScore = 1;
	}
	/// [2013-07-16] Charles. Added for supporting 'Zappit Rackcard'.
	/// [2013-08-08] Charles. Added codes checking player's score is not busted.
	else if(dealerTotal == m_dealerPushTotal && pPlayerBonus == 0x00 && playerScore>0) {
		// if forced push, make scores same
		playerScore = dealerScore;
		playerBonusTotal = dealerBonusTotal = 0;
	}
	else
	if (pDealerBonus)
	{
		dealerBonusTotal += pDealerBonus->GetBonusTotal();
		dealerBonusPayout += pDealerBonus->GetBonusPayout();
		*ppDealerBonusName = pDealerBonus->GetName();
	}

	//ordinal score
	playerScore += playerBonusTotal;
	dealerScore += dealerBonusTotal;

	if (playerScore > dealerScore)
	{
		//WIN
		payout += (int)(bet * m_payoutWin);

		payout += (int)(bet * playerBonusPayout);
	}
	else
	if (playerScore < dealerScore)
	{
		//LOSS
		payout += (int)(bet * m_payoutLoss);
	}
	else
	{
		//TIE
		payout += (int)(bet * m_payoutTie);
	}

	return payout;
}


void BJRules::GetDealScript( char** ppScript, int* pDealScriptLen )
{
	*ppScript		= &m_dealScript[0];
	*pDealScriptLen	= m_dealScriptLen;
}

int BJRules::IsStandardDeal()
{
	int i;
	int dCount=0;
	int DCount=0;
	int pCount=0;
	int PCount=0;
	for (i=0; i<m_dealScriptLen; i++)
	{
		if (m_dealScript[i] == 'd')
			dCount++;
		if (m_dealScript[i] == 'D')
			DCount++;
		if (m_dealScript[i] == 'p')
			pCount++;
		if (m_dealScript[i] == 'P')
			PCount++;
	}

	if (dCount==1)	//one down
	if (DCount==1)	//one up
	if (pCount==0)	//none down
	if (PCount==2)	//two up
	if (m_dealScriptLen==4)	//4 cards
		return 1;

	//non-standard deal
	return 0;
}

int BJRules::EndOfTurnDealer( BJHand* pDealer )
{
	if (CanDealer( EOG, pDealer, 1 ))
		return 1;

	if (GetDealerWinBonus( pDealer, 1 ))
		return 1;

	return 0;
}

int BJRules::EndOfTurnPlayer( BJHand* pPlayer, BJHand* pDealer, int nHands )
{
	if (CanPlayer( EOG, pPlayer, nHands ))
		return 1;

	if (GetDealerWinBonus( pDealer, nHands ))
		return 1;

	for (int i=0; i<nHands; i++)
	{

		//only look at standing hands
		if (IsPlayerHandAlive( pPlayer ))	
		{
			//gotta be a bonus hand
			BJBonus* pBonusPlayer = GetPlayerWinBonus( pPlayer, nHands, pDealer );
			if (!pBonusPlayer)
				return 0;

			int bonusTotalPlayer = pBonusPlayer->GetBonusTotal();

			//gotta beat dealer
			BJBonus* pBonusDealer = GetDealerWinBonusPossible( pDealer, nHands );
			if (pBonusDealer)
			{
				int bonusTotalDealer = pBonusDealer->GetBonusTotal();
				if (bonusTotalDealer >= bonusTotalPlayer)
					return 0;
			}
		}
		pPlayer = (BJHand*)pPlayer->getNextHand();
	}
	return 1;
}

void BJRules::AddRuleBonus
(
	char	who,			//dealer or player
	char	type,			//win or instant
	char*	pName,			//name of the bonus
	char*	pPattern,		//card pattern
	int		minHands,		//min hands to qualify
	int		maxHands,		//max hands to qualify
	int		minCards,		//min cards to qualify
	int		maxCards,		//max cards to qualify
	int		minTotal,		//min total to qualify
	int		maxTotal,		//max total to qualify
	int		minNBets,		//min number of bets
	int		maxNBets,		//max number of bets
	int		bonusTotal,		//bonus added to hand score
	float	bonusPayout,	//bonus payout in terms of the original bet
	char*	pPattern2		//card pattern 2
)
{
	if (m_nBonusRules >= MAXBONUSRULES)
		return;

	m_bonusRules[ m_nBonusRules ].SetBonus
	(
		who,			//dealer or player
		type,			//win or instant
		pName,			//name of the bonus
		pPattern,		//card pattern
		pPattern2,		//card pattern 2
		minHands,		//min hands to qualify
		maxHands,		//max hands to qualify
		minCards,		//min cards to qualify
		maxCards,		//max cards to qualify
		minTotal,		//min total to qualify
		maxTotal,		//max total to qualify
		minNBets,		//min number of bets
		maxNBets,		//max number of bets
		bonusTotal,		//bonus added to hand score
		bonusPayout		//bonus payout in terms of the original bet
	);

	//add one rule
	m_nBonusRules++;
}

void BJRules::AddRuleAction( BJAction* pAction )
{
	//check nRule limit
	if (m_nActionRules >= MAXACTIONRULES)
		return;

	//copy it
	m_actionRules[ m_nActionRules ] = *pAction;

	//add one rule
	m_nActionRules++;

}

void BJRules::AddRuleBonus( BJBonus* pBonus )
{
	//check nRule limit
	if (m_nBonusRules >= MAXBONUSRULES)
		return;

	//copy it
	m_bonusRules[ m_nBonusRules ] = *pBonus;

	//add one rule
	m_nBonusRules++;

}

void BJRules::AddRuleAction
(
	char		who,
	GameAction	action,
	int			minHands,
	int			maxHands,
	int			minCards,
	int			maxCards,
	int			minTotal,
	int			maxTotal,
	int			minSoft,
	int			maxSoft,
	char*		pPattern2,
	char*		pPattern //21 cards
)
{
	if (m_nActionRules >= MAXACTIONRULES)
		return;

	m_actionRules[ m_nActionRules ].SetAction
	(
		who,
		action,
		minHands,
		maxHands,
		minCards,
		maxCards,
		minTotal,
		maxTotal,
		minSoft,
		maxSoft,
		pPattern2,
		pPattern //21 cards
	);

	//add one rule
	m_nActionRules++;
}

int BJRules::IsPlayerHandBusted( BJHand* pPlayer )
{
	int isBusted = (pPlayer->GetScore() >= m_playerBustTotal);

	return isBusted;
}

int BJRules::IsPlayerHandAlive( BJHand* pPlayer )
{
	if (!pPlayer)
		return 0;

	if (IsPlayerHandBusted( pPlayer ))
		return 0;

	if (pPlayer->wasAction( BJF_SURRENDER ))
		return 0;

	return 1;
}

__int64 BJRules::GetDeckFilter()
{
	return m_deckFilter;
}

int BJRules::IsHardAces()
{
	return m_isHardAces;
}

int BJRules::IsSoftAces()
{
	return !IsHardAces();
}

void BJRules::SetDealScript( char* pScript )
{
	//gotta have a pointer
	if (pScript == NULL)
		return;

	//script can't be too large
	int len = strlen(pScript);
	if (len > sizeof(m_dealScript))
		return;
	m_dealScriptLen=len;

	memset(m_dealScript,0,sizeof(m_dealScript));

	strncpy(m_dealScript,pScript,sizeof(m_dealScript));
}

int BJRules::IsOffered( GameAction action )
{
	for (int i=0; i<m_nActionRules; i++)
	{
		BJAction* pAction= &m_actionRules[i];
		if (pAction->IsOffered( 'P', action ))
			return 1;
	}
	return 0;
}

int BJRules::GetActionsOffered()
{
	int options = 0;

	//get all the option flags
	int canBet			= IsOffered( Bet );
	int canHit			= IsOffered( Hit );
	int canStand		= IsOffered( Stand );
	int	canSplit		= IsOffered( Split );
	int canDouble		= IsOffered( Double );
	int canSurrender	= IsOffered( Surrender );
	int canZap= IsOffered( Zap );
	
	//set the individual bits
	if (canBet)			options |= OPTION_FLAG(Bet);
	if (canHit)			options |= OPTION_FLAG(Hit);
	if (canStand)		options |= OPTION_FLAG(Stand);
	if (canSplit)		options |= OPTION_FLAG(Split);
	if (canDouble)		options |= OPTION_FLAG(Double);
	if (canSurrender)	options |= OPTION_FLAG(Surrender);
	if (canZap)	options |= OPTION_FLAG(Zap);

	//return the set of player options
	return options;
}
